﻿using Windows.ApplicationModel.Core;
using Windows.Security.Credentials;
using Windows.UI.Text;
using Windows.UI.Xaml;
using InfoHub.Articles;
using InfoHub.Helpers;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;
using Windows.Web.Syndication;
using LinqToTwitter;
// using Newtonsoft.Json;

namespace InfoHub.Feeds
{
    public class RssFeed<T> : FeedBase where T : IArticle, new()
    {
        public override async Task<bool> ReadFromWeb()
        {
            if (this.Busy)
                return false;
            this.Busy = true;

            try
            {
                // fetch the feed 
                SyndicationFeed _Feed = null;


                try
                {
                    //if its twitter, we need different behavior than all prior rss/web type feeds
                    if (typeof(TwitterArticle) == typeof(T))
                    {
                        var _SearchResults = await ReadFromTwitterWebAsync();

                        //Populate a syndication feed to remain compliant with how the other feeds work.
                        _Feed = new SyndicationFeed();
                        foreach (var result in _SearchResults.Statuses)
                        {
                            //The link to the tweet
                            string _Uri = string.Format("https://twitter.com/#!/{0}/status/{1}", result.User.Identifier.ScreenName, result.StatusID);
                            _Feed.Items.Add(new SyndicationItem(result.Text,
                                new SyndicationContent(result.Text, SyndicationTextType.Text), new Uri(_Uri)));
                        }
                    }
                    else
                    {
                        _Feed = await ReadFromWebWithSyndication();
                    }
                }
                catch (Exception ex)
                {
                    Debug.WriteLine(ex);
                }
                if (_Feed == null)
                    try { _Feed = await ReadFromWebWithAlternative(); }
                    catch { this.InError = true; }
                if (_Feed == null)
                {
                    // rss feed
                    Debug.WriteLine("Error reading: " + this.SourceUrl);
                    // System.Diagnostics.Debugger.Break();
                    // setting inerror to true will remove it from the UI
                    this.InError = true;
                    return false;
                }

                // map in feed properties
                this.Title = this.Title ?? _Feed.Title.Text;

                // merge items from feed
                var _List = new List<T>();
                foreach (var item in _Feed.Items)
                {
                    var _Article = new T();
                    _Article.MapProperties(item, _Feed);
                    _List.Add(_Article);
                }
                base.MergeArticles(_List as IEnumerable<IArticle>);
                this.Updated = DateTime.Now;
                await base.WriteToCache();
                return true;
            }
            catch (Exception ex)
            {
                Debug.WriteLine("Error: " + ex.Message);
                System.Diagnostics.Debugger.Break();
                return false;
            }
            finally
            {
                this.Busy = false;
            }
        }

        async Task<Search> ReadFromTwitterWebAsync()
        {
            
            var consumerKey = AppHubViewModel.Strings.ConsumerKey;
            var consumerSecret = AppHubViewModel.Strings.ConsumerSecret;

            //See if we have the tokens stored. This is the portion twitter returns AFTER
            //the client has approved the oAuth request. We store them for future use so as not to 
            //prompt the user every time. 
            var accessToken = PasswordVaultHelper.GetPassword("accessToken");
            var oAuthToken = PasswordVaultHelper.GetPassword("oAuthToken");

            var consumerKeyStored = PasswordVaultHelper.GetPassword("consumerKey");
            var consumerSecretStored = PasswordVaultHelper.GetPassword("consumerSecret");

            if (consumerKey != consumerKeyStored || consumerSecret != consumerSecretStored)
            {
                //Do not use our stored accessToken or oAuthToken as it seems the consumerKey
                //or consumerSecret has changed. This would happy if the app has been deployed with a
                //new oAuth consumerKey or consumerSecret - as in the developer created new keys for their app.
                //Note I've seen scenarios where the old oAuth prompt from Twitter would appear _after_ changing keys
                //as if the old page was cached. I looked at the WebAuthenticationBroker logs and they seemed to 
                //be returning the proper token so not sure what was going on there. If it happens after changing keys
                //to new dev.twitter.com oauth consumerKey and consumerSecret, then give it a little time.
                accessToken = "";
                oAuthToken = "";
                //Store the blank keys for now to reset state, we'll overwrite below to ensure everything matches.
                PasswordVaultHelper.RemoveAllCredentials();

                //Save our current credentials.
                PasswordVaultHelper.SavePassword("consumerKey", consumerKey);
                PasswordVaultHelper.SavePassword("consumerSecret", consumerSecret);
            }


            var auth = new WinRtAuthorizer
            {
                Credentials = new LocalDataCredentials
                {
                    ConsumerKey = consumerKey,
                    ConsumerSecret = consumerSecret,
                    AccessToken = accessToken,
                    OAuthToken = oAuthToken
                },
                UseCompression = true,
                Callback = new Uri("http://application2.local")
            };

            if (!auth.IsAuthorized)
            {
                await auth.AuthorizeAsync();

                //Store the tokens if we've successfully auth'd. These should technically
                //be valid forever provided the consumer key isn't revoked. 
                if (auth.IsAuthorized)
                {
                    PasswordVaultHelper.SavePassword("accessToken", auth.Credentials.AccessToken);
                    PasswordVaultHelper.SavePassword("oAuthToken", auth.Credentials.OAuthToken);
                }
            }

            //Perform our search
            var twitterCtx = new TwitterContext(auth);

            var queryResults =
                from s in twitterCtx.Search
                where s.Type == SearchType.Search &&
                      s.Query == this.Keywords
                select s;

            var search = queryResults.Single();
            return search;
        }


        async Task<SyndicationFeed> ReadFromWebWithSyndication()
        {
            // fetch latest from the internet
            var _Uri = new Uri(this.SourceUrl);
            var _Feed = await new SyndicationClient().RetrieveFeedAsync(_Uri);
            return _Feed;
        }

        async Task<SyndicationFeed> ReadFromWebWithAlternative()
        {
            // including user agent, otherwise FB rejects the request
            var _Client = new HttpClient();
            var _UserAgent = "Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.2; WOW64; Trident/6.0)";
            _Client.DefaultRequestHeaders.Add("user-agent", _UserAgent);

            // fetch as string to avoid error
            var _Uri = new Uri(this.SourceUrl);
            var _Response = await _Client.GetAsync(_Uri);
            var _String = await _Response.Content.ReadAsStringAsync();

            // convert to xml (will validate, too)
            var _XmlDocument = new Windows.Data.Xml.Dom.XmlDocument();
            _XmlDocument.LoadXml(_String);

            // manually fill feed from xml
            var _Feed = new Windows.Web.Syndication.SyndicationFeed();
            _Feed.LoadFromXml(_XmlDocument);
            return _Feed;
        }
    }
}
